<?php
/**********************
**device.inc
**Date Created: 4/13/2009
**Copyright 2009 Tomorrow Tech Industries
**Contact: RPITomorrowTech@gmail.com
**********************/

require_once("shared/errors.inc");
require_once("dba.inc");

class Device
{	
	//For debugging
	private static $lastError;

	/*******
	Member variables
	*******/
	private $id;

	/********
	Initialization
	********/
	
	//Constructor
	public function Device($deviceId)
	{
		$this->id = $deviceId;
	}
	
	//Create an empty device
	static function createNewDevice(&$deviceId, $fields)
	{
		//FIXME: how do we get back the device Id?
		//There should only be a single device
		$type = '0';
		if( isset($fields['type']) )
		{
			$type = $fields['type'];
		}
		$name = 'Unnamed device';
		if( isset($fields['name']) )
		{
			$name = $fields['name'];
		}
		$state = '0';
		if( isset($fields['state']) )
		{
			$state = $fields['state'];
		}
		
		//Make sure a device by this name doesn't already exist
		if( TT_SUCCEEDED(Device::getDeviceByName($name, $existingDevice)) )
		{
			Device::setLastError("device name " . $name . " already exists");
			return TT_GENERAL;
		} 
		
		//Escape the values
		$type = DBaccess::GetSQLValueString($type, 'int');
		$name = DBaccess::GetSQLValueString($name, 'text');
		$state = DBaccess::GetSQLValueString($state, 'int');

		//id is auto-incremented to form its value
		$q = "INSERT INTO Device (type, name, state) VALUES ($type, $name, $state)";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		
		//Seems auto increment will not repeat deleted values (ie even if holes are present)
		$q = "SELECT MAX(devID) FROM Device WHERE name=$name";
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		$row = mysql_fetch_array($result);
		$deviceId = $row[0];
		
		return TT_OK;
	}
	
	/*********
	Utility
	*********/
	
	//Returns an array of device Ids
	//TODO: convert this to Device objects
	public static function getDevices(&$devices)
	{
		$q = "SELECT devID from Device ORDER BY devID";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		$devices = array();

		//Add in all of the device IDs
		while( $row = mysql_fetch_array($result) )
		{
			array_push($devices, $row[0]);
		}

		return TT_OK;
	}
		
	public static function getLastError()
	{
		return Device::$lastError;
	}
	
	public static function clearLastError()
	{
		Device::$lastError = '';
	}
	
	protected static function setLastError($error)
	{
		Device::$lastError = $error;
	}
	
	//All get requests are essentially the same
	//Get a single column value matching the current device id
	private function getColumn($column, &$value)
	{
		//There should only be a single device
		$q = "SELECT $column FROM Device WHERE devID='{$this->id}' LIMIT 1";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError("Couldn't execute query: " . $q);
			return $rc;
		}
		$row = mysql_fetch_array($result);
		$value = $row[0];
		return TT_OK;
	}
		
	//All gst requests are essentially the same
	//Update a single column matching the current device id to a certain value
	//Value must already be escaped prior to entering this function
	private function setColumn($column, $value)
	{
		//There should only be a single device
		//Example: the following are equivilent:
		$q = "UPDATE Device SET $column=$value WHERE devID={$this->id} LIMIT 1";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError($db->getLastError());
			return $rc;
		}

		return TT_OK;
	}
	
	//Return a mapped list of $portId => $deviceObject list of devices
	public static function getDevicesByStripId($stripId, &$devices)
	{
		//Use to look for matching devices
		$rc = Device::getDevices($allDevices);
		if( TT_FAILED($rc) )
		{
			return $rc;
		}

		$stripId = DBaccess::GetSQLValueString($stripId, 'int');

		//Start with no devices
		$devices = array();

		$q = "SELECT devID, portNum FROM Port WHERE stripID=" . $stripId;
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError($db->getLastError());
			return $rc;
		}

		//Loop for each row we got
		while( $row = mysql_fetch_array($result) )
		{
			//Extract fields
			$devId = $row[0];
			$portNum = $row[1];
			//Construct our device
			$device = new Device($devId);
			//map it 
			array_push($devices, array('port' => $portNum, 'device' => $device));
		}

		return TT_OK;
	}

	//Return a device object matching given name
	public static function getDeviceByName($nameIn, &$deviceOut)
	{
		$rc = Device::getDevices($devices);
		if( TT_FAILED($rc) )
		{
			return TT_FAILED;
		}

		foreach( $devices as $key => $value )
		{
			$id = $value;
			$device = new Device($id);
			if( TT_FAILED($device->getName($name)) )
			{
				return TT_FAILED;
			}
			if( $name == $nameIn )
			{
				$deviceOut = $device;
				return TT_OK;
			}
		}
		return TT_GENERAL;
	}

	//TODO: move this to a DeviceType class?
	//Returns an array of device information
	//Each element has an array such that
	// element[0]: typeID
	// element[1]: name
	static function getDeviceTypes(&$types)
	{
		$q = "SELECT typeID, name FROM DeviceTypes";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError($db->getLastError());
			return $rc;
		}
		
		//Start out with empty array
		$types = array();

		//Loop for each row we got
		while( $row = mysql_fetch_array($result) )
		{
			array_push($types, array($row[0], $row[1]));
		}
		return TT_OK;
	}

	static function addDeviceType(&$id, $args)
	{
		if( !isset($args['name']) )
		{
			return TT_GENERAL;
		}
		$name = DBaccess::GetSQLValueString($args['name'], 'text');
		
		if( !isset($args['iconPath']) )
		{
			return TT_GENERAL;
		}
		$iconPath = DBaccess::GetSQLValueString($args['iconPath'], 'text');

		$q = "INSERT INTO DeviceTypes(name, iconPath) VALUES(" . $name . "," . $iconPath . ")";
		$db = new DBaccess(); 
		$rc = $db->executeQuery($q, $result);
		if( TT_FAILED($rc) )
		{
			Device::setLastError('Query: ' . $q . ', error message: ' . $db->getLastError());
			return $rc;
		}
		
		//Add successfull, we are done
		return TT_OK;
	}

	/*****
	Accessor/mutator
	*****/
	
	public function getDeviceId(&$deviceId)
	{
		$deviceId = $this->id;
		return TT_OK;
	}
	
	//Device id is relativly immutable, in this object
	//It should only be changed if the database itself is changed
	public function setDeviceId($deviceId)
	{
		$deviceId = DBaccess::GetSQLValueString($deviceId, 'int');
		$rc = $this->setColumn("devID", $deviceId);
		//Only update this id if it really was updated
		if( TT_SUCCEEDED($rc) )
		{
			$this->id = $deviceId;
		}
		return $rc;
	}

	public function getType(&$type)
	{
		return $this->getColumn("type", $type);
	}

	public function setType($type)
	{
		return $this->setColumn("type", DBaccess::GetSQLValueString($type, 'int'));
	}

	public function getName(&$name)
	{
		return $this->getColumn("name", $name);
	}

	public function setName($name)
	{
		return $this->setColumn("name", DBaccess::GetSQLValueString($name, 'text'));
	}

	public function getState(&$state)
	{
		return $this->getColumn("state", $state);
	}

	public function setState($state)
	{
		return $this->setColumn("state", DBaccess::GetSQLValueString($state, 'int'));
	}
	
	public function getString()
	{
		$ret = "id: " . $this->id;
		return $ret;
	}

	//Test it
	public static function testDevice()
	{
		//Device::createNewDevice($devId, array('type' => '1', 'name' => 'VCR'));
		if( TT_FAILED(Device::getDevices($devices)) )
		{
			echo "Failed to get devices!<BR>";
		}
		else
		{
			if( count($devices) == 0 )
			{
				echo "No devices!<BR>\n";
			}
			else
			{
				echo "Devices:<BR>\n";
				foreach( $devices as $key => $value )
				{
					echo "Device id: $value<BR>";
					$device = new Device($value);
					
					Device::testGetter($device, "getDeviceId");
					Device::testGetter($device, "getType");
					Device::testGetter($device, "getName");
					Device::testGetter($device, "getState");
				}
			}
		}
	
		return true;
	}

	//Print member function tests
	public static function testGetter($device, $function)
	{
		$rc = $device->$function($ret);
		//Begine the print
		echo "&nbsp;&nbsp;&nbsp;$function: ";
		if( TT_SUCCEEDED($rc) )
		{
			echo "$ret";
		}
		else
		{
			echo "ERROR: " . errorString($rc);
		}
		//End the line
		echo "<BR>\n";
		return $rc;
	}
}


?>
